<?php
date_default_timezone_set('PRC');
error_reporting(E_ALL);

/**
 * App根路径
 */
define('APP_PATH', realpath('..'));

// 常量
include APP_PATH . "/app/config/constant.php";

use Phalcon\Mvc\Application as BaseApplication,
    \Phalcon\DiInterface, Phalcon\Http\ResponseInterface,
    Phalcon\Mvc\Url as UrlResolver,
    \Phalcon\Events\Manager as EventsManager;

class Application extends BaseApplication {

    #region 变量

    /**
     * 配置信息
     * @var array
     */
    private $config;

    #endregion

    /**
     * 构造函数
     * @param \Phalcon\DiInterface|null $di
     */
    public function __construct(DiInterface $di) {

        if (isset($_GET['_url'])) {
            $_GET['_url'] = strtolower($_GET['_url']);
        }

        /**
         * 读取配置文件
         */
        $this->config = include APP_PATH . "/app/config/config.php";

        /**
         * 自动加载
         */
        $this->autoLoad();

        /**
         * 全局注册服务
         */
        $this->registerService($di);

        /**
         * 注册模版
         */
        $this->registerModules($this->config->module->register->toArray());

        /**
         * 设置DI
         */
        $this->setDI($di);
    }

    #region 执行请求

    /**
     * 处理请求
     * @return \Phalcon\Http\ResponseInterface
     */
    public function request() {

        /**
         * @var \Phalcon\Mvc\Router $router 路由对象
         * @var \Phalcon\Mvc\Dispatcher $dispatcher 调度器对象
         * @var \App\V1\Module $module
         */

        $di = $this->getDI();

        $router = $di->getShared("router");
        $router->handle();
        $dispatcher = $di->getShared('dispatcher');
        $moduleName = $dispatcher->getModuleName();
        $moduleConfig = $this->getModule($moduleName);
        if ($moduleConfig) {
            $path = $moduleConfig["path"];
            if (file_exists($path)) {
                include_once($path);
                $className = $moduleConfig["className"];
                $module = $di->get($className);
                $module->registerAutoloaders($di);
                $module->registerApps($di);
            }
        }
        // 通过调度器处理路由参数
        $dispatcher->dispatch();

        // 获取最后的返回结果
        $response = $dispatcher->getReturnedValue();
        //$response = $this->handle();

        if ($response instanceof ResponseInterface) {
            if (BUILD_VERSION != BUILD_RELEASE)
                \App\Helpers\LoggerHelper::info("响应结果：" . $this->response->getContent());
            $response->send();
        }
    }

    #endregion

    #region 自动加载

    /**
     * 自动加载
     */
    private function autoLoad() {
        $loader = new \Phalcon\Loader();

        /**
         * 从配置文件中注册文件夹
         */
        if (isset($this->config->dirs) && !empty($this->config->dirs)) {
            foreach ($this->config->dirs as $dir) {
                $dirs[] = $dir;
            }
            $loader->registerDirs($dirs, true);
        }

        /**
         * 从配置文件中注册命名空间
         */
        if (isset($this->config->namespaces) && !empty($this->config->namespaces)) {
            $loader->registerNamespaces($this->config->namespaces->toArray(), true);
        }

        $loader->register();
    }

    #endregion

    #region 注册服务

    /**
     * 注册服务
     * @param DiInterface $di
     */
    private function registerService(DiInterface &$di) {

        $config = $this->config;

        #region 将当前对象注册为app服务

        /**
         * 将当前对象注册为app服务
         */
        $di->set("app", $this);

        #endregion

        #region 注册相关配置

        /**
         * 注册相关配置
         */
        $di->setShared("config", $config);

        #endregion

        #region URL组件 ，用于生成各种应用程序的URL

        /**
         * URL组件，用于生成各种应用程序的URL
         */
        $di->setShared('url', function () use ($config) {
            $url = new UrlResolver();
            $url->setBaseUri($config->app->baseUri);
            return $url;
        });

        #endregion

        #region 注册路由

        /**
         * 注册路由
         */
        $di->setShared('router', function () use ($config) {
            return include APP_PATH . '/app/config/routes.php';
        });

        #endregion

        #region 注册调度器

        $di->setShared("dispatcher", function () use ($config, $di) {
            $dispatcher = new \App\Mvc\Dispatcher($config, $di);
            // 将循环调度事件绑定到事件管理器
            $dispatcher->attach();
            // 将循环调度事件绑定到事件管理器
            $dispatcher->setDispatcher();
            return $dispatcher;
        });

        #endregion

        #region 注册注释解析缓存适配器

        /**
         * 注册注释解析缓存适配器
         */
        $di->setShared("annAdapter", function () {
            if (BUILD_VERSION == BUILD_RELEASE) {
                $reader = new \App\Adapters\Annotations\ApcuAdapter();
            } else {
                $reader = new \Phalcon\Annotations\Adapter\Memory();
            }
            return $reader;
        });

        #endregion

        #region 注册数据签名加密组件

        /**
         * 注册数据签名加密组件
         */
        $di->setShared("sign", function () {
            return new \App\Helpers\RsaHelper();
        });

        #endregion

        #region 注册数据连接

        /**
         * 注册master数据库连接
         */
        $di->setShared('dbMaster', function () use ($config) {
            $dbConfig = $config->database->master->toArray();
            $connection = new Phalcon\Db\Adapter\Pdo\Mysql($dbConfig);
            $eventsManager = new EventsManager();
            $eventsManager->attach("db:beforeQuery", new \App\Plugins\DbListenerPlugin());
            $connection->setEventsManager($eventsManager);
            return $connection;
        });

        /**
         * 注册slave1数据库连接
         */
        $di->setShared('dbSlave1', function () use ($config) {
            $dbConfig = $config->database->slave1->toArray();
            $connection = new Phalcon\Db\Adapter\Pdo\Mysql($dbConfig);
            $eventsManager = new EventsManager();
            $eventsManager->attach("db", new \App\Plugins\DbListenerPlugin());
            $connection->setEventsManager($eventsManager);
            return $connection;
        });

        #endregion

        #region 注册Redis客户端组件

        /**
         * 注册Redis组件
         */
        $di->setShared('redis', function () use ($config) {
            $redis = new \App\Libraries\NoSql\RedisClient($config->redis);
            return $redis;
        });

        #endregion

        #region 注册缓存组件

        /**
         * 注册缓存组件
         */
        $di->setShared('cache', function () use ($di) {
            $cache = new \App\Cache\RedisCache();
            return $cache;
        });

        #endregion

        #region 注册队列组件

        /**
         * 注册队列组件
         */
        $di->setShared('queue', function () use ($di) {
            $queue = new \App\Queue\RedisQueue();
            return $queue;
        });

        #endregion

        #region 注册Mongodb客户端组件

        /**
         * 注册Mongodb客户端组件
         */
        $di->setShared('mongodb', function () use ($config) {
            if (class_exists("MongoDB\\Driver\\Manager")) {
                $mongodb = new \App\Libraries\NoSql\Mongodb\MongodbClient($config->mongodb);
            } else {
                $mongodb = new \App\Libraries\NoSql\Mongo\MongodbClient($config->mongodb);
            }
            return $mongodb;
        });

        #endregion

        #region 注册HTTP请求环境服务

        /**
         * 注册HTTP请求环境服务
         */
        $di->setShared("request", "App\\Http\\Request");

        #endregion

        #region 注册HTTP响应环境服务

        /**
         * 注册HTTP响应环境服务
         */
        $di->setShared("response", "App\\Http\\Response");

        #endregion

        #region 注册推送服务渠道

        /**
         * 注册推送服务渠道
         */
        $di->set("push", function () use ($config) {
            return new \App\Channels\JPushChannel($config->jPush);
        });

        #endregion

        #region 注册支付宝服务

        /**
         * 注册任务服务
         */
        $di->set("aliPay", function () use ($config) {
            return new \App\Services\AliPayService($config->aliPay);
        });

        #endregion

        #region 注册微信支付服务

        /**
         * 注册微信支付服务
         */
        $di->set("wxPay", function () use ($config) {
            return new \App\Services\WxPayService();
        });

        #endregion

        #region 注册In-Apple Purchase 服务

        $di->set("iap", function () use ($config) {
            return new \App\Services\InApplePurchaseService($config->iap);
        });

        #endregion
    }
    #endregion
}

try {
    $di = new Phalcon\Di\FactoryDefault();
    $app = new \Application($di);
    echo $app->request();
} catch (PDOException $e) {
    throw $e;
} catch (Exception $e) {
    throw $e;
}